#!/usr/bin/env python
# -*- coding:utf-8 -*-

# file:itemset.py
# author:邹煜扬
# datetime:2024/12/18 16:26
# software: PyCharm
"""
this is function  description 
"""
# import module your need
from models.grammar import Grammar
from models.item import Item

class ItemSet:
    def __init__(self, itemset,grammar):
        if itemset is None:
            self.itemset = set()#使用集合可以避免项目集中出现重复的项目
        else:
            self.itemset = itemset.itemset
        self.grammar = grammar

    def __iter__(self):#确保itemset是可迭代的
        return iter(self.itemset)


    def __eq__(self, other):
        if isinstance(other, ItemSet):
            return self.itemset == other.itemset
        return False
    def __hash__(self):
        return hash(frozenset(self.itemset))

    def add_item(self, item):
        self.itemset.add(item)

    def copy(self):
        return ItemSet(self.itemset,self.grammar)

    def after_dot_symbols(self):#求项目集中所有项目点后面的符号
        symbols = set()
        for item in self.itemset:
            symbols.add(item.after_dot_symbol())
        return symbols

    def next_nucleus(self, symbol):#求这个项目集经过符号symbol可以转移到的项目集的核
        next_nucleus=ItemSet(None, grammar=self.grammar)
        next_is_None = True
        for item in self.itemset:
            if item.after_dot_symbol() == symbol:
                next_nucleus_item=Item(item.production,item.dot_position)
                next_nucleus_item.dot_position += 1#转移之后点要后移一位
                if next_nucleus_item.dot_position >= len(next_nucleus_item.production.right):
                    next_nucleus_item.dot_position = len(next_nucleus_item.production.right)
                next_nucleus.add_item(next_nucleus_item)
                next_is_None = False
        if next_is_None:
            return None
        else:
            return next_nucleus

    def is_included(self, new_item):#判断一个项目是否在项目集中
        for item in self.itemset:
            if item.production == new_item.production and item.dot_position == new_item.dot_position:
                return True
        return False

    def closure(self):
        '''
        计算闭包函数
        :param itemset: 当前项目集的集合
        :return:
        '''

        # 初始化闭包集合，包含输入的项目集
        closure_itemset = ItemSet(self, self.grammar)
        # 标志用于迭代，表示是否有项目被添加到闭包中
        added = True

        # 循环直到没有新的项目添加到闭包中为止
        while added:
            # 将标志设为 False，表示没有新的项目添加到闭包中
            added = False

            # 对当前闭包集合中的每个项目进行遍历
            for item in closure_itemset.itemset.copy():

                # 如果点的位置不在项目的最后一个位置
                if item.dot_position < len(item.production.right):
                    # 获取点后面的符号
                    next_symbol = item.after_dot_symbol()

                    # 如果该符号在文法的非终结符中
                    if next_symbol in self.grammar.VN:
                        # 对该符号的每个产生式进行遍历
                        for production in self.grammar.P:
                            if production.left == next_symbol:
                                # 创建一个新项目，将点移动到产生式的开头
                                new_item = Item(production,0)
                            # 如果新项目不在闭包中，则添加到闭包中，并将标志设为 True
                                if closure_itemset.is_included(new_item) is False:
                                    closure_itemset.add_item(new_item)
                                    added = True

            # 处理以点结尾的项目的闭包
            for item in closure_itemset.itemset.copy():

                # 如果点在项目的最后一个位置
                if item.dot_position == len(item.production.right):
                    # 检查状态集中是否已经存在相同的状态
                    if closure_itemset.is_included(item) is False:
                        # 添加新项目到闭包中，并将标志设为 True
                        closure_itemset.add_item(item)
                        changed = True

        # #返回闭包的冻结集合，确保集合是不可变的
        # return frozenset(closure_itemset)
        closure_itemset=sorted(closure_itemset,key=lambda x:x.production.left)
        return closure_itemset

    def __repr__(self):
        str=""
        for item in self.itemset:
            str+=f"{item} "
        return str